#ifndef WIDGET_H
#define WIDGET_H

extern "C"
{
#define UINT64_C(c)     c ## ULL
#include "libavformat/avformat.h"
#include "libavutil/avstring.h"
#include "libavutil/pixdesc.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
#include "libavcodec/audioconvert.h"
#include "libavcodec/colorspace.h"
#include "libavcodec/opt.h"
#include "libavcodec/avfft.h"

#if 0x1
#include <SDL/SDL.h>
#include "my_SDL_compat.h"
#ifdef __MINGW32__
#undef main
#endif
#endif

}

#include <QtCore>
#include <QtGui>
#include <QtMultimedia>
////#include "t_pcm_audio_device.h"


class T_MutexLocker
{
public:
    QMutex *m_mutex;
    explicit T_MutexLocker(QMutex *a_mutex) : m_mutex(a_mutex)
    {
        m_mutex->lock();
    }
    ~T_MutexLocker()
    {
        m_mutex->unlock();
    }
};

class T_FPS
{
public:
    QTime m_time_line;
    double m_fps;
    int m_count;
    explicit T_FPS() : m_fps(0), m_count(0)
    {
    }
    bool wake()
    {
        if(!m_time_line.isNull()) return false;
        m_time_line.start();
        return true;
    }
    void restart()
    {
        m_count = 0;
        m_time_line.start();
    }
    void add(int a)
    {
        m_count += a;
    }
    double value()
    {
        if(m_time_line.isNull())
        {
            qDebug() << "[T_FPS.value()] warning: T_FPS.wake() was not called.";
            return 0;
        }
        else if(m_time_line.elapsed() < 1000)
        {
            return m_fps;
        }
        else
        {
            m_fps = 1000.0 * m_count / m_time_line.elapsed();
            restart();
            return m_fps;
        }
    }
};

class T_AVPicture
{
public:
    AVPicture m_av_picture;
    enum PixelFormat m_pix_fmt;
    int m_width;
    int m_height;
    int m_numBytes;
    quint8 *m_buffer;

    explicit T_AVPicture(PixelFormat a_pix_fmt, int a_width, int a_height)
        :
        m_pix_fmt(a_pix_fmt),
        m_width(a_width),
        m_height(a_height),
        m_numBytes(0),
        m_buffer(0)
    {
        reinit();
    }
    ~T_AVPicture()
    {
        if(m_buffer) delete[] m_buffer;
    }
    void resize(int a_width, int a_height)
    {
        if(m_width==a_width && m_height==a_height) return;
        m_width = a_width;
        m_height = a_height;
        reinit();
    }
protected:
    void reinit()
    {
        int v_numBytes=avpicture_get_size(
                m_pix_fmt,
                m_width,
                m_height
                );
        //qDebug() << "[v_numBytes][m_numBytes]" << v_numBytes << m_numBytes;
        if(m_numBytes < v_numBytes)
        {
            m_numBytes = v_numBytes;
            //qDebug() << "[m_numBytes]" << m_numBytes;
            if(m_buffer) delete[] m_buffer;
            m_buffer=new quint8[m_numBytes];
        }
        avpicture_fill(
                &m_av_picture,
                m_buffer,
                m_pix_fmt,
                m_width,
                m_height
                );
    }
};

class T_AVPacket
{
public:
    int m_frame_no;
    AVPacket m_av_packet;
};

class Widget;

#if 0x0
class T_VideoThread : public QThread
{
public:
    Widget *m_widget;
    explicit T_VideoThread(Widget *a_widget)
        : m_widget(a_widget)
    {
    }

    virtual void run();
};

class T_AudioThread : public QThread
{
public:
    Widget *m_widget;
    explicit T_AudioThread(Widget *a_widget)
        : m_widget(a_widget)
    {
    }

    virtual void run();
};
#endif

class T_ScreenWidget : public QWidget
{
public:
    QSize m_size;
    SDL_Surface *screen;

    explicit T_ScreenWidget(QWidget *parent = 0)
        : QWidget(parent)
        , m_size(QSize(200, 100))
    {
        //QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
        QSizePolicy sizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
        sizePolicy.setHorizontalStretch(1);
        sizePolicy.setVerticalStretch(1);
        sizePolicy.setHeightForWidth(this->sizePolicy().hasHeightForWidth());
        this->setSizePolicy(sizePolicy);
    }
    virtual void setScreenSize(QSize a_size)
    {
        m_size = a_size;
    }
    virtual QSize sizeHint () const
    {
        return m_size;

    }
protected:
#if 0x0
    virtual void resizeEvent (QResizeEvent * event)
    {
        Uint32 flags = 0;
        flags |= SDL_HWSURFACE;
        flags |= SDL_ASYNCBLIT;
        flags |= SDL_HWACCEL;
        flags |= SDL_RESIZABLE;
        screen = SDL_SetVideoMode(
                this->width(),
                this->height(),
                0,
                flags);
        QWidget::resizeEvent(event);
    }
#endif
};

class Generator : public QIODevice
{
    Q_OBJECT
public:
    Widget *m_widget;
    QByteArray m_audio_buffer;
    Generator(Widget *a_widget, QObject *parent)
        : QIODevice(parent)
        , m_widget(a_widget)
    {
        bool v_ok = QIODevice::open(QIODevice::ReadOnly);
        qDebug() << "[Generator::Generator()]" << v_ok;
    }
    ~Generator()
    {
        qDebug() << "[Generator::~Generator()]";
    }
    qint64 bytesAvailable() const
    {
        qDebug() << "[Generator::bytesAvailable()]";
        //return QIODevice::bytesAvailable();
        return 0;
    }
    qint64 writeData(const char *data, qint64 len)
    {
        qDebug() << "[Generator::writeData()]";
        Q_UNUSED(data);
        Q_UNUSED(len);
        return 0;
    }
    virtual qint64 readData(char *data, qint64 maxlen);
};

namespace Ui {
    class Widget;
}
class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private:
    Ui::Widget *ui;
public:
    T_ScreenWidget *screenWidget;

    AVFormatContext	*formatCtx;
    int	videoStream;
    int audioStream;
    AVCodecContext	*videoCtx;
    AVCodecContext	*audioCtx;
    AVCodec		*videoCodec;
    AVCodec		*audioCodec;
    AVFrame		*frame;
    int		frameFinished;
    QString		filename;
    int frameNo;
    QTimer m_video_timer;
    QTime m_time_line;
    ////QTime m_resize_time_line;
    int m_drop_count;
    AVStream *m_video_stream;
    AVStream *m_audio_stream;
    T_FPS m_fps1;
    T_FPS m_fps2;
    QQueue<T_AVPacket> m_video_packet_queue;
    QQueue<T_AVPacket> m_audio_packet_queue;
    QMutex m_frame_mutex;
    ////QByteArray m_audio_buffer;
    DECLARE_ALIGNED(16,quint8,m_audio_decode_array)[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
    DECLARE_ALIGNED(16,quint8,m_audio_convert_array)[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];

    SDL_Window *window_id;

    Generator *m_generator;
    QAudioDeviceInfo m_device;
    QAudioFormat m_format;
    QAudioOutput * m_audioOutput;

public slots:
    void onTimerTimeout();

#if 0x0
public:
    T_VideoThread m_video_thread;
    T_AudioThread m_audio_thread;
#endif
};

#endif // WIDGET_H
